package com.chen.base.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.chen.root.base.PageData;
import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * java.util.stream相关工具类
 * @author: Long
 * @date: 2023/7/23 8:11
 **/
@UtilityClass
public class StreamUtil {

    /**
     * java.util.stream流分页
     * 采用skip()跳过(当前页 - 1) * 页大小
     * 后使用limit()截取前pageSize数量的元素
     * @param list 待分页的数据集
     * @param currentPage 当前页
     * @param pageSize 页大小
     * @return 分页后的数据集
     * @param <T> 泛型T
     */
    public <T> List<T> page(List<T> list,Integer currentPage,Integer pageSize){
        return list.stream()
                .skip((currentPage - 1L) * pageSize).limit(pageSize)
                .collect(Collectors.toList());
    }

    /**
     * java.util.stream流分页
     * 采用skip()跳过(当前页 - 1) * 页大小
     * 后使用limit()截取前pageSize数量的元素
     * @param stream 待分页的java.util.stream流
     * @param currentPage 当前页
     * @param pageSize 页大小
     * @return 分页后的数据集
     * @param <T> 泛型T
     */
    public <T> PageData<T> pageResult(Stream<T> stream, Integer currentPage, Integer pageSize, Integer total){
        List<T> page = stream.skip((currentPage - 1L) * pageSize).limit(pageSize).collect(Collectors.toList());
        return PageData.build(currentPage,pageSize,(long)total,page);
    }

    /**
     * 数据源分组
     * @param list 数据源
     * @param classifier 组
     * @return 分组后的map
     * @param <T> 数据源元素T
     * @param <K> 泛型T中的属性K
     */
    public <T, K> Map<K, List<T>> groupBy(List<T> list, Function<? super T, ? extends K> classifier){
        return list.stream().collect(Collectors.groupingBy(classifier));
    }

    /**
     * 排序，如果属性为null，则排到最后面
     * @param list 数据源
     * @param keyEx 参与排序的属性
     * @param isAsc 是否升序
     * @return 排序后的数据集
     * @param <T> 数据源元素T
     * @param <U> 泛型T中的属性U
     */
    public <T, U> List<T> sort(List<T> list, Function<? super T, ? extends U> keyEx, Boolean isAsc){
        if (CollectionUtil.isEmpty(list)){
            return list;
        }

        Comparator nullsLast = null;
        U u = keyEx.apply(list.get(0));
        if (u instanceof Short){
            nullsLast = Comparator.nullsLast(Short::compareTo);
        } else if (u instanceof Integer){
            nullsLast = Comparator.nullsLast(Integer::compareTo);
        }else if (u instanceof Long){
            nullsLast = Comparator.nullsLast(Long::compareTo);
        }else if (u instanceof Float){
            nullsLast = Comparator.nullsLast(Float::compareTo);
        }else if (u instanceof Double){
            nullsLast = Comparator.nullsLast(Double::compareTo);
        }else if (u instanceof String){
            nullsLast = Comparator.nullsLast(String::compareTo);
        }else if (u instanceof Boolean){
            nullsLast = Comparator.nullsLast(Boolean::compareTo);
        }
        Assert.notNull(nullsLast, "不支持的排序类型!");
        Comparator<? super T> comparing = Comparator.comparing(keyEx, nullsLast);
        if (isAsc != null && !isAsc){
            comparing = comparing.reversed();
        }

        return list.stream().sorted(comparing).collect(Collectors.toList());
    }

    /**
     * 提取T中的属性U
     * @param list 数据源
     * @param mapper 需要提取的属性
     * @return U集
     * @param <T> 数据源元素T
     * @param <U> 泛型T中的属性U
     */
    public <T, U> List<U> map(List<T> list,Function<? super T, ? extends U> mapper){
        if (CollectionUtil.isEmpty(list)){
            return new ArrayList<>();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 过滤匹配处理
     * @param list 数据集
     * @param filter 过滤条件
     * @param consumer 数据消费逻辑
     * @param <T> 数据
     */
    public <T> void filterHandler(List<T> list, Predicate<T> filter, Consumer<T> consumer){
        list.stream().filter(filter).findFirst().ifPresent(consumer);
    }

}
